using Core;
using Google.Protobuf;
using SuperSocket.ProtoBase;
using SuperSocket.Server;

namespace Server;

public sealed class PlaySession : AppSession
{
    private readonly IPackageEncoder<BaseCommand> _encoder;
    private readonly PacketDispatcher _packetDispatcher = new();
    private readonly PacketIdentifierProvider _packetIdentifierProvider = new();
    
    public PlaySession(IPackageEncoder<BaseCommand> encoder)
    {
        _encoder = encoder;
    }

    public ulong UserId { get; set; }

    internal ValueTask SendPacketAsync(BaseCommand packet)
    {
        return Channel.SendAsync(_encoder, packet);
    }
    
    internal ValueTask DispatchAsync(BaseCommand command)
    {
        _packetDispatcher.TryDispatch(command);

        return ValueTask.CompletedTask;
    }
    
    internal async ValueTask<BaseCommand> SendAndReceivePacketAsync(
        BaseCommand command,
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        command.RequestId = _packetIdentifierProvider.GetNextRequestId();

        using var packetAwaitable = _packetDispatcher.AddAwaitable(command.RequestId);

        try
        {
            await SendPacketAsync(command);
        }
        catch (Exception e)
        {
            packetAwaitable.Fail(e);
            Logger.LogError(e, $"{UserId} 发送封包抛出一个异常 key：{command.Key}");
        }

        try
        {
            return await packetAwaitable.WaitAsync(cancellationToken);
        }
        catch (Exception e)
        {
            if (e is TimeoutException)
                Logger.LogError(e, $"{UserId} 等待封包调度超时 key：{command.Key}");

            throw;
        }
    }
}